package com.apes.fn.server.servicePlan.model;

import com.alibaba.fastjson.annotation.JSONField;
import com.apes.fn.crm.customer.FnCustomer;
import com.apes.fn.crm.customerExpand.FnCustomerExpand;
import com.apes.fn.server.servicePlan.service.ServicePlanceService;
import com.apes.fn.server.workOrder.service.MaintenanceOrderService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.DefaultPersistListener;
import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.comment.Comment;
import com.apes.framework.jpa.generator.ApesGenerator;
import com.apes.framework.plugin.fileserver.File;
import com.apes.framework.plugin.soe.annotations.State;
import com.apes.framework.plugin.soe.annotations.States;
import com.apes.framework.plugin.soe.metadata.BusinessAttributeValue;
import com.apes.framework.rop.session.SimpleSession;
import com.apes.framework.util.ApesConst;
import com.apes.framework.util.Arith;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MapUtil;
import com.apes.oap.session.RopSessionHolder;
import com.apes.scm.masterdata.car.model.CarConfiguration;
import com.apes.scm.masterdata.car.model.CarLabel;
import com.apes.scm.masterdata.car.model.CarModel;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.finance.model.CooperateType;
import com.apes.scm.masterdata.frame.model.Channel;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.UserRepository;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SelectBeforeUpdate;

import javax.persistence.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Creator: zouyc
 * CreateDate: 2019-12-30 15:56
 * Description:
 **/
@Getter
@Setter
@SelectBeforeUpdate
@DynamicInsert
@DynamicUpdate
@Entity
@EntityListeners(DefaultPersistListener.class)
@Table(name = ServicePlan.CONST_TABLE_NAME, indexes = {
        @Index(columnList = "source_from"),
        @Index(columnList = "PICK_CAR_NAME"),
        @Index(columnList = "PICK_CAR_DATE")
})
public class ServicePlan extends Model {
    public static final String CONST_TABLE_NAME = "ser_service_plan";
    public static final String CONST_INNER_SOURCE_SERVICEPLAN = "servicePlan";
    public static final String CONST_INNER_SOURCE_WORKORDER = "workOrder";

    @Id
    @Column(name = "id", nullable = false, length = 24)
    @ApesGenerator(code = CONST_TABLE_NAME, name = "方案编码",  padding = 5 , prefix = "FW%(company)%(yy)%(month)", useDateRange=true)
    private String id;

    @Column(name = "business_type", length = 32)
    @Comment("单据类型")
    private String businessType = "servicePlan";

    @Column(name = "business_type_name", length = 64)
    @Comment("单据类型名称")
    private String businessTypeName = "服务方案";

    @Column(name = "source_from", length = 20)
    @Comment("来源单号")
    private String sourceFrom; //来源

    @Column(name = "source_business_type", length = 32)
    @Comment("来源单据类型")
    private String sourceBusinessType;

    @Column(name = "source_business_type_name", length = 64)
    @Comment("来源单据类型名称")
    private String sourceBusinessTypeName;

    @Column(name = "supplier_ref", length = 20)
    @Comment("第三方单号")
    private String supplierRef;

    @Transient
    private boolean sourceFromAndBusinessType; //单据来源+来源单号
    public String getSourceFromAndBusinessType(){
        if (sourceFrom==null)return "";
        return this.sourceBusinessTypeName+"/"+this.sourceFrom;
    }
    public void setSourceFromAndBusinessType(String sourceFromAndBusinessType){
        return;
    }

    @Column(name = "inner_source_from", length = 16)
    @Comment("内部来源号")
    private String innerSourceFrom; //1.整单内协情况

    @Column(name = "inner_source_from_type", length = 16)
    @Comment("内部来源类型号")
    private String innerSourceFromType; //1.整单内协情况


    @Column(name = "old_frame_source_from", length = 16)
    @Comment("老框架方案号")
    private String oldFrameSourceFrom; //来源

    @Column(name = "lock_servicePlan", nullable = false, columnDefinition = "number(1,0) default 0")
    @Comment("锁住状态")
    private boolean lockServicePlan = false;

    @Column(name = "regex_result", nullable = false, columnDefinition = "number(1,0) default 0")
    @Comment("装配图匹配结果")
    private boolean regexResult = false;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "fn_customer_expand_id", referencedColumnName = "id")
    @Comment("赋能客户车辆扩展信息")
    private FnCustomerExpand fnCustomerExpand;

    @Column(name = "car_liscence", length = 255)
    @Comment("车牌（作并发锁用）")
    private String carLiscence; //车牌

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "company_id", referencedColumnName = "id", nullable = false)
    @Comment("公司")
    private PartyRole company;  //单据所属公司

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "belong_dept_id", referencedColumnName = "id", nullable = false)
    @Comment("方案门店")
    private Dept belongDept;  //区分，该单据属于哪个门店，权限用

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "sale_dept_id", referencedColumnName = "id", nullable = false)
    @Comment("结算门店")
    private Dept saleDept;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "service_dept_id", referencedColumnName = "id", nullable = false)
    @Comment("施工门店")
    private Dept serviceDept;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "channel", referencedColumnName = "id")
    @Comment("渠道")
    private Channel channel;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "cooperation_type", referencedColumnName = "id")
    @Comment("合作类型")
    private CooperateType cooperationType;

    @Column(name = "exchance_code", length = 64)
    @Comment("服务兑换码")
    private String exchanceCode;

    @Column(name = "safety_tips", length = 64)
    @Comment("安全提示")
    private String safetyTips;

    public void setState(String state) {
        if ("termination".equals(this.state)&&!"termination".equals(state)){
            throw new RuntimeException(serviceplanStateIdToName("termination")+"状态不允许更新为:"+serviceplanStateIdToName(state));
        }
        this.state = state;
    }

    @States(name = "方案状态", values = {
            @State(id = "create", name = "新增"),
            @State(id = "toTechAudit", name = "转技术审核"),
            @State(id = "techAudit", name = "技术审核完成"),
            @State(id = "backTechAudit", name = "技术审核退回"),
            @State(id = "toPriceAudit", name = "转价格审核"),
            @State(id = "priceAudit", name = "价格审核"),
            @State(id = "backPriceAudit", name = "价格审核退回"),
            @State(id = "toInquiry", name = "转询价"),
            @State(id = "inquiryFinish", name = "询价完成"),
            @State(id = "backInquiry", name = "询价退回"),
            @State(id = "submission", name = "提交"),
            @State(id = "goBack", name = "退回"),
            @State(id = "confirm", name = "确认"),
            @State(id = "qualityTest", name = "质检"),
            @State(id = "termination", name = "终止"),
//            @State(id = "toReceivables", name = "转收款"),  质检完成直接转收款
            @State(id = "receivables", name = "收款完成")
    })
    @Column(name = "state", length = 32, nullable = false)
    private String state ;

    public String getStateName() {
        return serviceplanStateIdToName(this.state);
    }

    public String serviceplanStateIdToName(String state) {
        switch (state){
            case"create":
                return "新增";
            case"toTechAudit":
                return "转技术审核";
            case"techAudit":
                return "技术审核完成";
            case"backTechAudit":
                return "技术审核退回";
            case"toPriceAudit":
                return "转价格审核";
            case"priceAudit":
                return "价格审核";
            case"backPriceAudit":
                return "价格审核退回";
            case"toInquiry":
                return "转询价";
            case"inquiryFinish":
                return "询价完成";
            case"backInquiry":
                return "询价退回";
            case"submission":
                return "提交";
            case"confirm":
                return "确认";
            case"qualityTest":
                return "质检";
            case"termination":
                return "终止";
            case"receivables":
                return "收款完成";
                default:
                    return this.state;
        }
    }

    @Transient
    private String stateName;


    //判断是否能转到对应状态
//    private void checkStateChance(String oldState, String newState, Map<String, String[]> state_chance_map) {
//        if(state_chance_map.containsKey(newState)){
//            String[] strings = state_chance_map.get(newState);
//            if(strings == null){
//                throw new RuntimeException("程序设置状态有误，请检查");
//            }else{
//                if(!Arrays.asList(strings).contains(oldState)){
//                    throw new RuntimeException("当前状态不可以进行该操作，请刷新界面重试");
//                }
//            }
//        }else{
//            throw new RuntimeException("程序设置状态有误，请检查");
//        }
//    }
    @States(name = "方案类型", values = {
            @State(id = "common", name = "普通"),
            @State(id = "someAssist", name = "部分内协"),
            @State(id = "lossSomeAssist", name = "定损部分内协"),//作废,勿用
            @State(id = "allAssist", name = "整单内协"),
    })
    @Column(name = "plan_type", columnDefinition = "varchar2(64) default 'common'", nullable = false)
    private String planType = "common";

    public boolean checkToTechAudit(){
        return this.state == "toTechAudit" ? true : false;
    }

    public boolean checkToPriceAudit(){
        return this.state == "toPriceAudit" ? true : false;
    }

    public boolean checkToInquiry(){
        return this.state == "toInquiry" ? true : false;
    }

    @Column(name = "sales_amount", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("方案结算金额")
    private double salesAmount = 0;  //工时费 + 配件 ，不包含管理费等其他 [同意服务标记为真的都计算]

    @Column(name = "balance_amount", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("方案结算金额")
    private double balanceAmount = 0;  //工时 + （领用数量-归还数量   *   优惠单价）  【同意服务的 + 非终止的】
    public double getBalanceAmount(){
        if(this.qualityTestDate == null ){
            if(this.servicePlanItems != null){
                return caculateBalanceAmount();
            }else{
                return 0;
            }
        }else{
            return this.balanceAmount;
        }
    }
    @Column(name = "claim_Amount", columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("理赔金额")
    private double claimAmount = 0;

    @Column(name = "sum_management_cost", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("管理费用")
    private double sumManagementCost = 0;

    /**
     * 计算明细上的主表合计金额
     */
    public void computeSum(){
        double salesAmount = 0; //销售金额，当确认日期为空，都进行统计（方案确认后，这个金额不进行统计）
        double sumManagementCost = 0;//销售金额，当确认日期为空，都进行统计（方案确认后，这个金额不进行统计）
        double balanceAmount = 0 ;//方案确认不为空，质检日期不为空，结算日期为空的时候，进行操作都统计
        double referTaxPlan = 0;
        setItemDetail();
        for(ServicePlanItem servicePlanItem : this.servicePlanItems){
            if(servicePlanItem.getTerminationDate() == null && servicePlanItem.isServiceState()){
                salesAmount += servicePlanItem.getSalesAmount();
                sumManagementCost += servicePlanItem.getManagementCost();
                balanceAmount += servicePlanItem.balanceAmount();
                referTaxPlan += Arith.mul(servicePlanItem.getReferTax(),servicePlanItem.getSaleQty());
            }
        }
        this.salesAmount = Arith.round(salesAmount,2);
        this.sumManagementCost = Arith.round(sumManagementCost,2);
        this.referTaxPlan = Arith.round(referTaxPlan,2);
        this.referTaxProfitPlan = Arith.round(Arith.sub(salesAmount,referTaxPlan),2);
        if(this.confirmDate != null && this.receivableDate == null){
            this.balanceAmount = Arith.round(balanceAmount,2);
        }
    }

    @Transient
    private double serviceCost = 0;

    @Transient
    @Comment("总费用")
    private double sumCost = 0;
    public void setSumCost(){
        this.sumCost = Arith.round(this.serviceCost + this.salesAmount,0);
    }

    @Column(name = "price_review_comments", length = 250)
    @Comment("价格审核意见")
    private String priceReviewComments;

    @Column(name = "technical_audit_comments", length = 250)
    @Comment("技术审核意见")
    private String technicalAuditComments;

    @Column(name = "qualified_flag")
    @Comment("方案合格标记(qualified:合格,Unqualified:不合格)")
    private String qualifiedFlag;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "scheme_confirmation_method", referencedColumnName = "id")
    @Comment("方案确认方式")
    private Enumeration schemeConfirmationMethod;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "to_technical_audit_uid", referencedColumnName = "id")
    @Comment("转技术审核人")
    private PartyRole toTechnicalAuditUid;

    @JSONField(format = DateUtil.SHOW_DATETIME_FORMAT)
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "to_technical_audit_date")
    @Comment("转技术审核日期")
    private Date toTechnicalAuditDate;


    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "technical_audit_uid", referencedColumnName = "id")
    @Comment("技术审核人")
    private PartyRole technicalAuditUid;

    @JSONField(format = DateUtil.SHOW_DATETIME_FORMAT)
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "technical_audit_date")
    @Comment("技术审核日期")
    private Date technicalAuditDate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "back_technical_audit_uid", referencedColumnName = "id")
    @Comment("技术退回人")
    private PartyRole backTechnicalAuditUid;

    @JSONField(format = DateUtil.SHOW_DATETIME_FORMAT)
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "back_technical_audit_date")
    @Comment("技术退回日期")
    private Date backTechnicalAuditDate;

    @Column(name = "tech_audit_opinion", length = 2000)
    @Comment("技术审核意见")
    private String techAuditOpinion; //来源

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "to_price_audit_uid", referencedColumnName = "id")
    @Comment("转价格审核人")
    private PartyRole toPriceAuditUid;

    @JSONField(format = DateUtil.SHOW_DATETIME_FORMAT)
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "to_price_audit_date")
    @Comment("转价格审核日期")
    private Date toPriceAuditDate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "price_audit_uid", referencedColumnName = "id")
    @Comment("价格审核人")
    private PartyRole priceAuditUid;

    @JSONField(format = DateUtil.SHOW_DATETIME_FORMAT)
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "price_audit_date")
    @Comment("价格审核日期")
    private Date priceAuditDate;

    @Column(name = "price_audit_opinion", length = 2000)
    @Comment("价格审核意见")
    private String priceAuditOpinion; //来源

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "back_price_audit_uid", referencedColumnName = "id")
    @Comment("价格退回人")
    private PartyRole backPriceAuditUid;

    @JSONField(format = DateUtil.SHOW_DATETIME_FORMAT)
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "back_price_audit_date")
    @Comment("价格退回日期")
    private Date backPriceAuditDate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "to_inquiry_uid", referencedColumnName = "id")
    @Comment("转询价人")
    private PartyRole toInquiryUid;

    @JSONField(format = DateUtil.SHOW_DATETIME_FORMAT)
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "to_inquiry_date")
    @Comment("转询价日期")
    private Date toInquiryDate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "submission_uid", referencedColumnName = "id")
    @Comment("提交人")
    private PartyRole submissionUid;

    @JSONField(format = DateUtil.SHOW_DATETIME_FORMAT)
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "submission_date")
    @Comment("提交日期")
    private Date submissionDate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "go_back_uid", referencedColumnName = "id")
    @Comment("退回人")
    private PartyRole goBackUid;

    @JSONField(format = DateUtil.SHOW_DATETIME_FORMAT)
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "go_back_date")
    @Comment("退回日期")
    private Date goBackDate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "confirm_uid", referencedColumnName = "id")
    @Comment("确认人")
    private PartyRole confirmUid;

    @JSONField(format = DateUtil.SHOW_DATETIME_FORMAT)
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "confirm_date")
    @Comment("确认日期")
    private Date confirmDate;

    @Column(name = "quality_test_state")
    @Comment("质检结果(qualified:合格,Unqualified:不合格)")
    private String qualityTestState;

    @Column(name = "quality_test_date")
    @Comment("最后质检时间")
    private Date qualityTestDate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "quality_test_uid", referencedColumnName = "id")
    @Comment("质检人")
    private PartyRole qualityTestUid;

    @JSONField(format = DateUtil.SHOW_DATETIME_FORMAT)
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "receivable_date")
    @Comment("收款日期")
    private Date receivableDate;

    public boolean checkReceivable(){
        return this.getReceivableDate() != null ? true : false;
    }

    @JSONField(format = DateUtil.SHOW_DATETIME_FORMAT)
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "estimated_delivery_date")
    @Comment("预计交车时间")
    private Date estimatedDeliveryDate;

    public String getGetCarInfo() {
//        if (this.getCarInfo==null)return "--";
        return getCarInfo;
    }

    public void insertGetCarInfoForMap(Map getCarInfo) {
        if (getCarInfo.isEmpty()) {
            Date date = new Date();
            String format = DateUtil.format(date, DateUtil.SHOW_DATETIME_FORMAT);
            String name;
            if (get_creator() != null) {
                name = get_creator().getName();
            } else {
                /**获取当前上下文的用户信息**/
                SimpleSession session = (SimpleSession) RopSessionHolder.get();
                if (session == null) return;
                name = session.getUserName();
            }
            this.getCarInfo = name + " - " + format;
            this.pickCarName = name;
            this.pickCarDate = date;
            return;
        }
        Object newCarInfo = getCarInfo.get("carInfo");
        Object id = getCarInfo.get("id");
        Object pickCarType = getCarInfo.get("pickCarType");
        Object creator = getCarInfo.get("creator");
        Object createDate = getCarInfo.get("createDate");
        this.getCarInfo = (String) newCarInfo;
        this.pickCarId = (String) id;
        this.pickCarType = (String) pickCarType;
        this.pickCarName = (String) creator;
        this.pickCarDate = (Date) createDate;

    }

    @Column(name = "getCarInfo", length = 250)
    @Comment("接车信息")
    private String getCarInfo ;

    @Column(name = "pick_car_name", length = 36)
    @Comment("接车人")
    private String pickCarName ;

    @JSONField(format = DateUtil.SHOW_DATETIME_FORMAT)
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "pick_Car_Date")
    @Comment("接车日期")
    private Date pickCarDate ;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "termination_uid", referencedColumnName = "id")
    @Comment("终止人")
    private PartyRole terminationUid;

    @JSONField(format = DateUtil.SHOW_DATETIME_FORMAT)
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "termination_date")
    @Comment("终止日期")
    private Date terminationDate;

//    @Column(name = "remark", length = 250)
//    @Comment("备注")
//    private String remark;

    @Column(name = "customer_remarks", length = 1000)
    @Comment("车主备注")
    private String customerRemarks;

    @Column(name = "dept_remark", length = 1000)
    @Comment("门店备注")
    private String deptRemark;

    @Column(name = "fault_description", length = 2000)
    @Comment("故障描述")
    private String faultDescription;

    @Column(name = "diagnose_result", length = 2000)
    @Comment("诊断结果")
    private String diagnoseResult;

    @Column(name = "finish_work", nullable = false, columnDefinition = "number(1,0) default 0")
    @Comment("方案施工完成标记")
    private boolean finishWork = false;


    @File
    @Lob
    @Comment("定损清单")
    @Basic(fetch = FetchType.LAZY)
    @Column(name = "loss_List", columnDefinition = "CLOB")
    private String lossList;

    @Column(name = "get_Car_Type", length = 256)
    @Comment("接车类型")
    private String getCarType;

    @Column(name = "pick_Car_Id", length = 36)
    @Comment("接车单号")
    private String pickCarId;

    @Column(name = "pick_Car_Type", length = 36)
    @Comment("接车单据类型")
    private String pickCarType;

    @States(name = "方案服务类型", values = {
            @State(id = "A", name = "正常维修"),
            @State(id = "B", name = "质保返修")
    })
    @Comment("方案服务类型")
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "serve_type",  referencedColumnName = "id")
    private BusinessAttributeValue serveType;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "verification_uid", referencedColumnName = "id")
    @Comment("核销人")
    private PartyRole verification;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "insurance_discounts", referencedColumnName = "id")
    @Comment("车险优惠方案")
    private Enumeration insuranceDiscounts;

    @Column(name = "out_system_business", columnDefinition = "number(1,0)")
    @Comment("体系外合作单位业务")
    private boolean outSystemBusiness = false;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "car_configuration_id", referencedColumnName = "id")
    @Comment("车型配置")
    private CarConfiguration carConfiguration;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "car_model_id", referencedColumnName = "id")
    @Comment("车型")
    private CarModel carModel;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "car_label_id", referencedColumnName = "id")
    @Comment("厂牌")
    private CarLabel carLabel;

    @Column(name = "refer_tax_plan", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("参考成本")
    private double referTaxPlan = 0;

    @Column(name = "refer_tax_profit_plan", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("参考毛利")
    private double referTaxProfitPlan = 0;

    @Transient
    private String carServiceLevel;
    public String getCarServiceLevel(){
        if (this.carServiceLevel==null) return "";
        return this.carServiceLevel;
    }

    @Transient
    private boolean inquiryPoint;
    public boolean isInquiryPoint(){
        for(ServicePlanItem servicePlanItem : servicePlanItems){
            if(servicePlanItem.getOldInquiryNumber() != null) return true;
        }
        return false;
    }

    @OneToMany(mappedBy = "servicePlan", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<PickUpTypeS> pickUpTypeS = new ArrayList();

    public List<PickUpTypeS> getPickUpTypeS() {
        if(pickUpTypeS == null) return new  ArrayList();
        for (PickUpTypeS item : pickUpTypeS) {
//            if("T1".equals(item.getPickUpType().getId()) && (item.getRemarks() == null || "".equals(item.getRemarks().trim()))){
//                throw new RuntimeException("接车类型为其他，必须填写备注信息");
//            }
            item.setServicePlan(this);
        }
        return pickUpTypeS;
    }

    public void setPickUpTypeS(List<PickUpTypeS> pickUpTypeS){
        this.pickUpTypeS.clear();
        if (pickUpType != null && pickUpType.size() != 0) {
            List<PickUpTypeS> list = pickUpType.stream().map(
                    item -> {
                        PickUpTypeS pickUpTypeS1 = new PickUpTypeS();
                        pickUpTypeS1.setPickUpType(item);
                        return pickUpTypeS1;
                    }
            ).collect(Collectors.toList());
            this.pickUpTypeS.addAll(list);
        }
    }

    @OneToMany(mappedBy = "servicePlan", cascade = CascadeType.ALL, orphanRemoval = true)
    @OrderBy("sort")
    private List<ServicePlanItem> servicePlanItems = new ArrayList<ServicePlanItem>(); //从表
    public List<ServicePlanItem> getServicePlanItems(){
        for(ServicePlanItem servicePlanItem : servicePlanItems){
            servicePlanItem.setServicePlan(this);
        }
        return servicePlanItems;
    }

    public void setServicePlanItems(List<ServicePlanItem> servicePlanItems){
        if (servicePlanItems == null)  servicePlanItems = new ArrayList<ServicePlanItem>();
        this.servicePlanItems.clear();
        this.servicePlanItems.addAll(servicePlanItems);

    }

    @Transient
    private boolean toTechAuditFlag; //转技术审核标记
    public boolean getToTechAuditFlag(){
        boolean flag = false;

        if(this.submissionDate == null && !this.state.equals("termination") && this.technicalAuditDate == null
                && !this.state.equals("toTechAudit") && !this.state.equals("toPriceAudit") && !this.state.equals("toTechAudit")
                && !this.state.equals("toInquiry") && this.lockServicePlan == false && !this.state.equals("backTechAudit") && !this.state.equals("backPriceAudit")
                && this.belongDept.getId().equals(this.serviceDept.getId())) flag = true;
        return flag;
    }

    @Transient
    private boolean backTechAuditFlag; //技术退回
    public boolean getBackTechAuditFlag(){
        boolean flag = false;
        if(this.state.equals("toTechAudit") && !this.state.equals("termination")) flag = true;
        return  flag;
    }

    @Transient
    private boolean techAuditFlag; //技术审核
    public boolean getTechAuditFlag(){
        boolean flag = false;
        if(this.state.equals("toTechAudit") && !this.state.equals("termination")) flag = true;
        return  flag;
    }

    @Transient
    private boolean toPriceAuditFlag; //转价格审核
    public boolean getToPriceAuditFlag(){
        boolean flag = false;

        if(this.submissionDate == null && !this.state.equals("termination") && !this.state.equals("toPriceAudit")
                && !this.state.equals("toTechAudit") && !this.state.equals("toInquiry") && !this.state.equals("backTechAudit")) flag = true;
        return flag;
    }

    @Transient
    private boolean backPriceAuditFlag; //价格退回
    public boolean getBackPriceAuditFlag(){
        boolean flag = false;
        if(this.state.equals("toPriceAudit") && !this.state.equals("termination")) flag = true;
        return  flag;
    }

    @Transient
    private boolean priceAuditFlag; //价格审核
    public boolean getPriceAuditFlag(){
        boolean flag = false;
        if(this.state.equals("toPriceAudit") && !this.state.equals("termination")) flag = true;
        return  flag;
    }

    @Transient
    private boolean toInquiryFlag; //转询价
    public boolean getToInquiryFlag(){
        boolean flag = false;
        if(this.submissionDate == null && !this.state.equals("toInquiry") && !this.state.equals("termination")
                && !this.state.equals("toTechAudit") && !this.state.equals("toPriceAudit") && this.lockServicePlan == false && !this.state.equals("backTechAudit")
                && this.belongDept.getId().equals(this.serviceDept.getId())) flag = true;
        return flag;
    }

    @Transient
    private boolean submissionFlag; //提交
    public boolean getSubmissionFlag(){
        boolean flag = false;
        if(!this.state.equals("toTechAudit") && !this.state.equals("toPriceAudit") && !this.state.equals("toInquiry")
                && this.submissionDate == null && !this.state.equals("termination") && !this.state.equals("backTechAudit"))
            flag = true;
        return  flag;
    }

    @Transient
    private boolean confirmFlag; //确认
    public boolean getConfirmFlag(){
        boolean flag = false;
        if(this.state.equals("submission") && !this.state.equals("termination")) flag = true;

        return  flag;
    }



    @Transient
    private boolean goBackFlag; //退回标记
    public boolean getGoBackFlag(){
        boolean flag = false;
        if(this.confirmDate == null && this.submissionDate != null && !this.state.equals("termination")) flag = true;
        return  flag;
    }

    @Transient
    private boolean terminationFlag; //方案确认前终止标记
    public boolean getTerminationFlag(){
        boolean flag = false;
        if (!this.state.equals("termination") && !this.state.equals("toPriceAudit") && this.belongDept.getId().equals(this.serviceDept.getId())
                && !this.state.equals("toTechAudit") && !this.state.equals("toInquiry") && !this.state.equals("backTechAudit")
                && (this.oldFrameSourceFrom == null || (this.oldFrameSourceFrom != null && this.saleDept.getId().equals(this.serviceDept.getId())))
        ) flag = true;

        if (this.qualityTestDate != null && !this.belongDept.getId().equals(this.saleDept.getId()))
            flag = false;
        //判断是否有可终止明细（无可种植行，设置为false）
        if(this.getServicePlanItems() != null && this.getServicePlanItems().size() != 0){
            List list = this.getServicePlanItems().stream().filter(ServicePlanItem::checkCanEnd).collect(Collectors.toList());

            if(list.size() == 0) flag = false;
        }
        return  flag;
    }

    @Transient
    private boolean editFlag; //修改标记
    public boolean getEditFlag(){
        boolean flag = false;
        if(this.state.equals("create")
                || this.state.equals("techAudit")
                || this.state.equals("priceAudit")
                || this.state.equals("inquiryFinish")
                || this.state.equals("backInquiry")
                || this.state.equals("goBack")
                || this.state.equals("backPriceAudit")
                 ) flag = true;
        return  flag;
    }

    /**
     * 计算明细上的相关信息
     */
    public void setItemDetail(){
        for(ServicePlanItem servicePlanItem : servicePlanItems){
            if(servicePlanItem.getSaleQty() <= 0)
                throw new RuntimeException(servicePlanItem.getProduct().getId() + "商品销售数不能小于等于0");

            if(this.getSubmissionDate() != null && servicePlanItem.isServiceState()
                    && servicePlanItem.getQtyEnd() != servicePlanItem.getSaleQty()){
                if(servicePlanItem.getPftPriceUnit() <= 0)
                    throw new RuntimeException(servicePlanItem.getProduct().getId() + "商品销售金额不能小于等于0");

                if(servicePlanItem.getPriceUnit() <= 0)
                    throw new RuntimeException(servicePlanItem.getProduct().getId() + "商品销售金额不能小于等于0");

                if(this.getState() != null && this.getState().equals("submission") && servicePlanItem.getSalesAmount() <= 0)
                    throw  new RuntimeException(servicePlanItem.getProduct().getId() + "商品金额有误，请检查后提交");
            }

            //单品销售金额
            servicePlanItem.setSalesAmount(
                    servicePlanItem.SaleAmount()
            );
            //折扣率
            if(servicePlanItem.getPrimaryPriceUnit() !=0) servicePlanItem.setDiscountRate(
                   servicePlanItem.calculateDiscountRate()
            );
            //管理费用  优惠价格*管理费率*销售件数
            servicePlanItem.setManagementCost(
                    servicePlanItem.calcalateManagementCost()
            );
        }
    }

    @Transient
    private boolean extraServiceFlag; //方案确认是否生成额外工单：整单内协助
    public boolean getExtraServiceFlag(){
        boolean result = false;
        if(!this.serviceDept.getId().equals(this.saleDept.getId())
                && this.belongDept.getId().equals(this.serviceDept.getId())) result = true;
        return  result;
    }


    @Transient
    private boolean orderFlag; //方案确认是否生成工单标记
    public boolean getOrderFlag(){
        boolean result = false;
        if(this.belongDept.getId().equals(this.saleDept.getId())) result = true;
        return  result;
    }

    @Transient
    private boolean twoOrderFlag; //方案确认是否生成双边工单标记  内协方，普通方
    public boolean getTwoOrderFlag(){
        boolean result = false;
        if(this.belongDept.getId().equals(this.saleDept.getId()) &&
                !this.belongDept.getId().equals(serviceDept.getId())
                && !this.serviceDept.getId().equals(this.saleDept.getId())) result = true;
        return  result;
    }

    @Transient
    private PartyRole _creator;
    @Transient
    public PartyRole get_creator() {
        if(this.getCreator() == null) return null;
        return SpringManager.getBean(PartyRoleRepository.class).findOne(this.getCreator());
    }
    @Transient
    private FnCustomer _customer;

    @Transient
    private Map customer;
    public Map getCustomer() {
        if (fnCustomerExpand == null || fnCustomerExpand.getMobile() == null) return null;
        return MapUtil.mapper(
                "realname", fnCustomerExpand.getRealname(),
                "mobile", fnCustomerExpand.getMobile(),
                "nameAndPhone",fnCustomerExpand.getRealname()+" "+fnCustomerExpand.getSecretMobile(),
                "level", fnCustomerExpand.getCustomerLevelId(),
                "vendorCode", fnCustomerExpand.getVendorCode(),
                "userRole", MapUtil.mapper(
                        "id", fnCustomerExpand.getUserRoleId(),
                        "name", fnCustomerExpand.getUserRoleName()
                )
        );
    }

    @Transient
    private Map customerCar;
    public Map getCustomerCar() {
        if (fnCustomerExpand == null || fnCustomerExpand.getCarLicense() == null) return null;
        return MapUtil.mapper(
                "carLicense", fnCustomerExpand.getCarLicense(),
                "customer", this.getCustomer(),
                "vendorCode", fnCustomerExpand.getVendorCode(),
                "jekunModelCode",fnCustomerExpand.getJekunModelCode(),
                "vin", fnCustomerExpand.getVin(),
                "carServiceLevel",getCarServiceLevel(),
                "carModelLabel",fnCustomerExpand.getCarModelLabel(),
                "unitClient",MapUtil.mapper(
                        "clientCode",fnCustomerExpand.getUnitClientId()
                )
        );
    }

    @Transient
    private Map fnCustomerExpandTemp;
    public Map getFnCustomerExpandTemp(){
        return this.getCustomerCar();
    }

    @Transient
    private String orderOrigin;  //单据的做单来源
    public static final String CONST_SERVICEPLAN_ORDERORIGIN_APP = "APP";


    @Transient
    private PartyRole operator1;  //系统外的操作员

    private double caculateBalanceAmount(){
        if(this.servicePlanItems == null) return 0;
        double balanceAmount = 0;
        for(ServicePlanItem servicePlanItem : this.servicePlanItems){
            balanceAmount += servicePlanItem.balanceAmount();
        }
        return balanceAmount;
    }

    @Transient
    private boolean needTechAudit = false;

    public boolean getNeedTechAudit() {
        if( this.state.equals("toTechAudit") || this.state.equals("backTechAudit")){
            return SpringManager.getBean(ServicePlanceService.class).isToTechnical(this);
        } else {
            return false;
        }
    }

    /**
     * 是否检查库存
     */
    @Transient
    private boolean checkStock = false;

    public boolean getCheckStock() {
        if (this.channel==null)return true;
        String channelId = this.channel.getId();
        switch (channelId){
            case "75":
            case "70":
            case "50":
            case "100":
                return false;
            case "80":
                if ("app订单(车险优惠)".equals(this.sourceBusinessTypeName))return false;
        }
        if( "app订单(车险优惠)".equals(this.sourceBusinessTypeName))return false;
        return true;
    }

    /***
     * 限价级别
     * （限制在当前OA节点审批权限）
     */
    @Comment("价格审批限价级别")
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "price_limit_level", referencedColumnName = "id")
    private Enumeration priceLimitLevel; //限价级别

    /***
     * 用于铺平OA变量
     */
    @Transient
    private int priceLimitLevelCode;
    public int getPriceLimitLevelCode() {
        if( (this.state.equals("toPriceAudit") || this.state.equals("backPriceAudit") || this.state.equals("backPriceAudit") ||  ( this.receivableDate == null && this.confirmDate != null && !this.state.equals("termination") ))
                && this.priceLimitLevel != null ){
            return Integer.valueOf(this.priceLimitLevel.getCode());
        } else {
            return 5;
        }
    }

    // 技术审批发起人
    @Transient
    private String toTechAuditUserId;
    public String getToTechAuditUserId(){
        if(!this.state.equals("backTechAudit") && !this.state.equals("toTechAudit")) return null;
        User user = SpringManager.getBean(UserRepository.class).findByPartyRole(this.getToTechnicalAuditUid()).get(0);
        return user.getId().toString();
    }

    /**
     * 是否基地方案操作
     * @return
     */
    public boolean checkInnerServicePlan(){
        if(!this.belongDept.getId().equals(this.saleDept.getId())) return true;
        return false;
    }

    /**
     * 用到地方：返回质检队列，质检明细，完成质检接口用到
     * 根据传入类型返回，固定类型明细（有效）
     * @return
     */
    public List<ServicePlanItem> returnTypeItems(String type){
        List<ServicePlanItem> list = new ArrayList<>();
        switch (type){
            case "cosmetology": //洗车，美容
                list.addAll(this.servicePlanItems.stream().filter((servicePlanItem)->{
                    String id = servicePlanItem.getProduct().queryServeType().getId();
                    return servicePlanItem.getFinishDate() != null
                            && servicePlanItem.isServiceState()
                            && servicePlanItem.getTerminationDate() == null
                            && (id.equals("001") || id.equals("002"))
                            && (servicePlanItem.getAssistType().getId().equals("ServicePlanItem.assistType.outer")
                            || "20".equals(servicePlanItem.getProduct().getProductGroup().getId())
                            || servicePlanItem.isNeedQualityFlag());
                }).collect(Collectors.toList()));

                break;
            case "machineRepa": //保养 维修 改装 信息 服务 轮胎
                list.addAll(
                        this.servicePlanItems.stream().filter((servicePlanItem)->{
                            String id = servicePlanItem.getProduct().queryServeType().getId();
                            return servicePlanItem.getFinishDate() != null
                                    && servicePlanItem.isServiceState()
                                    && servicePlanItem.getTerminationDate() == null
                                    && (!id.equals("001") && !id.equals("002") && !id.equals("007") )
                                    && (servicePlanItem.getAssistType().getId().equals("ServicePlanItem.assistType.outer")
                                    || "20".equals(servicePlanItem.getProduct().getProductGroup().getId())
                                    || servicePlanItem.isNeedQualityFlag());
                        }).collect(Collectors.toList())
                );
                break;
            case "sprayPaint": //钣金喷漆
                list.addAll(
                        this.servicePlanItems.stream().filter((servicePlanItem)->{
                            String id = servicePlanItem.getProduct().queryServeType().getId();
                            return servicePlanItem.getFinishDate() != null
                                    && servicePlanItem.isServiceState()
                                    && servicePlanItem.getTerminationDate() == null
                                    && id.equals("007")
                                    && (servicePlanItem.getAssistType().getId().equals("ServicePlanItem.assistType.outer")
                                    || "20".equals(servicePlanItem.getProduct().getProductGroup().getId())
                                    || servicePlanItem.isNeedQualityFlag());

                        }).collect(Collectors.toList())
                );
                break;
                default:
                    return new ArrayList();
        }

        //判断该方案，该类型是否全部完工，如果存在未完工，不返回该类型质检


        return list;
    }

    public List<ServicePlanItem> returnNeedQualityTestItems(){
        return this.servicePlanItems.stream().filter(servicePlanItem -> servicePlanItem.getFinishDate() != null
                && servicePlanItem.isServiceState()
                && servicePlanItem.getQualityTestDate() == null
                && servicePlanItem.getTerminationDate() == null
                && (servicePlanItem.getAssistType().getId().equals("ServicePlanItem.assistType.outer")
                || "20".equals(servicePlanItem.getProduct().getProductGroup().getId())
                || servicePlanItem.isNeedQualityFlag())).collect(Collectors.toList());
    }

    public ServicePlanItem checkNoNeedQualityTest(){
        return this.servicePlanItems.stream().filter(servicePlanItem -> servicePlanItem.getFinishDate() != null
                && servicePlanItem.isServiceState()
                && servicePlanItem.getTerminationDate() == null
                && (servicePlanItem.getAssistType().getId().equals("ServicePlanItem.assistType.outer")
                || "20".equals(servicePlanItem.getProduct().getProductGroup().getId())
        )).filter(servicePlanItem -> !servicePlanItem.isNeedQualityFlag()).findFirst().orElse(null);

    }

    /**
     * 根据类型，判断该组质检完成情况
     * 1.待质检 2.质检合格 3.质检不合格
     * @param type
     * @return
     */
    public String checkFinishQualityTestByStyle(String type){
        List<ServicePlanItem> servicePlanItems = this.returnTypeItems(type);

        List<ServicePlanItem> list = servicePlanItems.stream().filter(servicePlanItem -> {
            return servicePlanItem.getFinishDate() != null && servicePlanItem.getQualityTestDate() == null && servicePlanItem.isServiceState();
        }).collect(Collectors.toList());
        if(list.size() > 0) return "waitQualityTest";

        list = servicePlanItems.stream().filter(servicePlanItem -> {
            return servicePlanItem.getFinishDate() != null && servicePlanItem.getQualityTestDate() != null
                    && servicePlanItem.isServiceState() && servicePlanItem.isQualityFlag() == false;
        }).collect(Collectors.toList());
        if(list.size() > 0) return "unstandard";

        return "standard";
    }

    /**
     * 是否存在需要施工商品
     * @return
     */
    public boolean checkWorkProduct(){
        List list = this.servicePlanItems.stream().filter((servicePlanItem)->{
            return "20".equals(servicePlanItem.getProduct().getProductGroup().getId()) && servicePlanItem.getTerminationDate() == null && servicePlanItem.isServiceState();
        }).collect(Collectors.toList());

        if(list.size() !=0) return true;
        return false;
    }

    /**
     * 是否存在需要质检商品
     * @return
     */
    public boolean checkQualityTestProduct(){
        List list = this.servicePlanItems.stream().filter((servicePlanItem)->{
            return servicePlanItem.isServiceState() && servicePlanItem.getTerminationDate() == null &&
                    ("20".equals(servicePlanItem.getProduct().getProductGroup().getId())
                            || servicePlanItem.getAssistType().getId().equals("ServicePlanItem.assistType.outer") || servicePlanItem.isNeedQualityFlag()); //上线历史数据（工时为1，配件为0，带安为1），剩下内协后外协的商品人工调整
        }).collect(Collectors.toList());

        if(list.size() !=0) return true;
        return false;
    }

    /**
     * 方案确认后有效
     * 根据方案明细，检测方案完成施工，还是终止
     * @return
     */
    public String checkResultByItem(){
        if(this.confirmDate == null) throw new RuntimeException("方案未确认，无需判断是否完成或终止");
        List<ServicePlanItem> servicePlanItems = this.getServicePlanItems().stream().filter(servicePlanItem -> {
//            if(servicePlanItem.getFinishDate() != null && servicePlanItem.getTerminationDate() != null)
//                throw new RuntimeException("方案明细同时处于终止与完成状态，程序出错,方案明细行编码：" + servicePlanItem.getId());
            return servicePlanItem.isServiceState() && servicePlanItem.getFinishDate() == null &&  servicePlanItem.getTerminationDate() == null;
        }).collect(Collectors.toList());
        if(servicePlanItems.size() > 0) return "unDone";
        List<ServicePlanItem> finishLists = this.getServicePlanItems().stream().filter(servicePlanItem -> {
            return servicePlanItem.isServiceState() && servicePlanItem.getFinishDate() != null && servicePlanItem.getTerminationDate() == null;
        }).collect(Collectors.toList());
        if(finishLists.size() > 0) return "finish";
        return "termination";
    }

    /**
     * 检测是否质检完成
     * @return
     */
    public boolean checkQualityResultByItem(){
        if(!this.isFinishWork())
            return false;
        List<ServicePlanItem> servicePlanItems = this.getServicePlanItems().stream().filter(servicePlanItem -> {
            return servicePlanItem.isServiceState() && servicePlanItem.getTerminationDate() == null &&  servicePlanItem.getQualityTestDate() == null;
        }).collect(Collectors.toList());

        if(servicePlanItems.size() == 0){
            return true;
        }else{
            return false;
        }
    }

    /**
     * 整单内协助，门店方案
     * @return
     */
    public boolean allInnerBelongSide(){
        if(this.getBelongDept().getId().equals(this.saleDept.getId())
                && !this.belongDept.getId().equals(this.serviceDept.getId())) return true;
        return false;
    }
    /**
     * 整单内协助，基地方案
     * @return
     */
    public boolean allInnerOtherSide(){
        if(!this.getBelongDept().getId().equals(this.saleDept.getId())
                && this.belongDept.getId().equals(this.serviceDept.getId())) return true;
        return false;
    }

    /***
     * 判断跨公司整单内协(门店方案)
     */
    public boolean crossCompanyAllInnerBelongSide() {
        if(this.getBelongDept().getId().equals(this.saleDept.getId())
                && !this.belongDept.getId().equals(this.serviceDept.getId())
                && !this.belongDept.getCompany().getId().equals(this.serviceDept.getCompany().getId())) return true;
        return false;
    }

    @Transient
    private List<Enumeration> pickUpType= new ArrayList();
    public List<Enumeration> getPickUpType() {
        if(this.pickUpTypeS == null) return new  ArrayList();
        return  pickUpTypeS.stream().map(PickUpTypeS::getPickUpType).collect(Collectors.toList());
    }

    @Transient
    private boolean oldFrameQualityForVoucher  = false;

    /**
     * 1.根据无父类，父类相同的一组分成两组
     * 2.有父类的：工时，同意
     * @param servicePlanItems
     * @return
     */
    public List<ServicePlanItem> sortFotErp(List<ServicePlanItem> servicePlanItems){
        //判断是否存在拥有父类的商品
        servicePlanItems.stream()
                .filter(lowLevel -> lowLevel.getHigherLevelCode()!=null&&!lowLevel.getHigherLevelCode().isEmpty())
                //如果明细存在子类 父类却不存在则清空
                .forEach(servicePlanItem -> {
                    boolean noneMatch = servicePlanItems.stream().noneMatch(higherLevel -> higherLevel.getProduct().getId().equals(servicePlanItem.getHigherLevelCode()));
                    if (noneMatch)servicePlanItem.setHigherLevelCode("");
                });

        Map firstGroupMap =
                servicePlanItems.stream().collect(
                        Collectors.groupingBy(servicePlanItem ->{
                            return servicePlanItem.getHigherLevelCode() == null ? "" : servicePlanItem.getHigherLevelCode();
                        })
                );
        //1.有父类作为主排，先进行筛选，无父类的后续插进去
        List<ServicePlanItem> firstStepYes = new ArrayList<>();
        List<ServicePlanItem> firstStepNo = new ArrayList<>();

        firstGroupMap.forEach((K,V)->{
            if(K.equals("")){
                firstStepYes.addAll((Collection<? extends ServicePlanItem>) V);
            } else{
                firstStepNo.addAll((Collection<? extends ServicePlanItem>) V);
            }
        });

        List<ServicePlanItem> fatherList = afterList(sortCommonMap(firstStepYes)).stream().sorted(Comparator.comparing(servicePlanItem -> servicePlanItem.getProduct().getId())).collect(Collectors.toList());
        List<ServicePlanItem> list = new ArrayList<>();
        Map<String, List<ServicePlanItem>> collect = fatherList.stream().collect(Collectors.groupingBy(servicePlanItem -> servicePlanItem.getProduct().getProductGroup().getId()));
        List<ServicePlanItem> hourWork = collect.get("10")!=null?collect.get("10"):new ArrayList<>();
        List<ServicePlanItem> fittings = collect.get("20")!=null?collect.get("20"):new ArrayList<>();
        for (int i = 0; i < fatherList.size(); i++) {
            if (i%2==0&&!hourWork.isEmpty()){
                list.add(hourWork.remove(0));
            }else if (!fittings.isEmpty()){
                list.add(fittings.remove(0));
            }else if (!hourWork.isEmpty()){
                list.add(hourWork.remove(0));
            }

        }
        fatherList=list;
        List<ServicePlanItem> sonList = afterList(sortCommonMap(firstStepNo));

        //将子类绑定再父类下面
        List<ServicePlanItem> resultList = new ArrayList<>();
        fatherList.forEach(servicePlanItem -> {
            resultList.add(servicePlanItem);
            resultList.addAll(sonList.stream().filter(servicePlanItem1 -> {
                return servicePlanItem.getProduct().getId().equals(servicePlanItem1.getHigherLevelCode());
            }).collect(Collectors.toCollection(ArrayList::new)));
        });

        if(servicePlanItems.size() != fatherList.size() + sonList.size()){
            throw new RuntimeException("方案排序有误，请重新查询");
        }
        return resultList;
    }

    private Map<String,List<ServicePlanItem>> sortCommonMap(List<ServicePlanItem> servicePlanItems){
        return servicePlanItems.stream().collect(
                Collectors.groupingBy(servicePlanItem ->{
                    String sortType = "";
                    sortType = sortType + ("20".equals(servicePlanItem.getProduct().getProductGroup().getId()) ? 1 : 0);
                    sortType = sortType + (servicePlanItem.isServiceState() ? 1 : 0);
                    sortType = sortType + (servicePlanItem.isAssessmentSituation() ? 1 : 0);
                    return sortType;
                })
        );
    }

    private List<ServicePlanItem> afterList(Map<String,List<ServicePlanItem>> map){
        Set set = map.keySet();
        List<String> list = (List) set.stream().map(item ->{
            return item;
        }).collect(Collectors.toCollection(ArrayList::new));
        list.sort(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return Integer.parseInt((String)o1) >= Integer.parseInt((String)o2)? -1 : 1;
            }
        });
        List<ServicePlanItem> resultLsit = new ArrayList<>();
        list.forEach(item ->{
            map.forEach((k,v)->{
                if(k.equals(item))  resultLsit.addAll(sortForCatefory(v));
            });

        });
        return resultLsit;
    }

    private List<ServicePlanItem> sortForCatefory(List<ServicePlanItem> servicePlanItems){
        List list = new ArrayList();
        Map<String,List<ServicePlanItem>> map =
                servicePlanItems.stream().collect(
                        Collectors.groupingBy(servicePlanItem ->{
                            return servicePlanItem.getProduct().getCategory() == null ? "" : servicePlanItem.getProduct().getCategory().getId();
                        })
                );
        map.forEach((k,v)->{
            list.addAll(v);
        });
        return list;
    }

    @Transient
    private boolean confirmEdit;
    public boolean getConfirmEdit() {
        String  state = this.getState();
        if(Objects.equals("submission",state) ||  Objects.equals("confirm",state) || Objects.equals("qualityTest",state) )
            return false;
        return true;
    }

    @Transient
    private String orderTypeTemp = "服务方案";

    public Integer getServiceStateFlag() {
        if (this.submissionDate!=null)return 0;
        return serviceStateFlag;
    }

    @Transient
    private Integer serviceStateFlag = 1;

    public Double getSalesAmountShow() {
        if (this.submissionDate!=null)return this.salesAmount;
        return getAllSalesAmount();
    }

    @Transient
    private Double salesAmountShow;

    public Double getAllSalesAmount() {
        return this.servicePlanItems.stream().mapToDouble(ServicePlanItem::getSalesAmount).sum();
    }

    @Transient
    private Double allSalesAmount;

    @Transient
    private List<String> errorMsg;
    public void addErrorMsg(String msg){
        this.errorMsg = this.errorMsg==null?this.errorMsg=new ArrayList<String>(): this.errorMsg;
        this.errorMsg.add(msg);
        this.errorMsg = this.errorMsg.stream().distinct().collect(Collectors.toList());
    }

    public Boolean getWorkOrderFlag() {
        if (confirmDate==null||receivableDate!=null)return false;
        Map map = SpringManager.getBean(MaintenanceOrderService.class).structureMaintenanceByServicePlan(this,"none",false);
        return (Boolean) map.get("inOutFlag");
    }

    public boolean isCopyFlag() {
        if (!"termination".equals(this.getState()))return false;
        if ("定损报价单".equals(this.getSourceBusinessTypeName()))return false;
        if (!this.getPlanType().equals("common"))return false;
        if (this.getOldFrameSourceFrom()!=null)return false;
        return true;
    }

    @Transient
    private boolean copyFlag;


    public Double totalEstimatedCommission() {
        return this.getServicePlanItems().stream().mapToDouble(i -> i.getEstimatedCommission() * (i.getSaleQty() - i.getQtyEnd())).sum();
    }

    @Transient
    private Boolean workOrderFlag = false;

    @Transient
    private double workAmountShow;
    public double getWorkAmountShow(){
        return this.servicePlanItems.stream().filter(ServicePlanItem::isServiceState)
                .filter(i -> i.getProduct().getProductGroup().getId().equals("20"))
                .mapToDouble(ServicePlanItem::getSalesAmount).sum();
    }

    @Transient
    private double partAmountShow;
    public double getPartAmountShow(){
        return this.servicePlanItems.stream().filter(ServicePlanItem::isServiceState)
                .filter(i -> i.getProduct().getProductGroup().getId().equals("10"))
                .mapToDouble(ServicePlanItem::getSalesAmount).sum();
    }

    @Transient
    private double commissionAmountShow;
    public double getCommissionAmountShow(){
        return this.servicePlanItems.stream().filter(ServicePlanItem::isServiceState)
                .mapToDouble(i -> Arith.mul((i.getSaleQty() - i.getQtyEnd()),i.getEstimatedCommission())).sum();
    }

    @Transient
    private boolean promptConfirm = false;

    @Transient
    private int chooseWarehouse = 0;

    public boolean isAutoDispatchProcess() {
        if (autoDispatchProcess){
            autoDispatchProcess = false;
            return true;
        }
        return false;
    }

    @Transient
    private boolean autoDispatchProcess = false;

    @Transient
    private String pageName = "none";

    public String getCarModelTemp() {
        String temp = "";
        if (carModel!=null)temp = temp + carModel.getName()+" ; ";
        if (carLabel!=null)temp = temp + "厂牌: " + carLabel.getName()+" ; ";
        if (carConfiguration!=null)temp = temp + "配置车型: " +  carConfiguration.getName();
        return temp;
    }

    @Transient
    private String carModelTemp ;

    public String getEstimatedDeliveryDateTemp() {
        if (estimatedDeliveryDate==null)return null;
        String format = DateUtil.format(this.estimatedDeliveryDate, DateUtil.SHOW_DATE_FORMAT);
        return format;
    }

    @Transient
    private String estimatedDeliveryDateTemp ;

    /**
     * 检查是否为大单
     *
     * @return 是否大于20条明细
     */
    public boolean checkBigBusiness() {
        if (servicePlanItems.size() > 20) return true;
        return false;
    }
}
